#ifndef SIMPLEAPP3_H_
#define SIMPLEAPP3_H_

#include "CEGuiD3D10BaseApplication.h"

ID3D10Texture2D*            g_pDepthStencil = NULL;
ID3D10DepthStencilView*     g_pDepthStencilView = NULL;
ID3D10EffectMatrixVariable* g_pWorldVariable = NULL;
ID3D10EffectMatrixVariable* g_pViewVariable = NULL;
ID3D10EffectMatrixVariable* g_pProjectionVariable = NULL;
D3DXMATRIX                  g_World;
D3DXMATRIX                  g_World2;
D3DXMATRIX                  g_View;
D3DXMATRIX                  g_Projection;

struct SimpleVertex
{
    D3DXVECTOR3 Pos;
    D3DXVECTOR4 Color;
};

class SimpleApp: public CEGuiD3D10BaseApplication
{
public:

    HRESULT createScene()
    {
        HRESULT hr = S_OK;

        bvRenderer = new BvD3D10Renderer(pimpl->d_device);

        SubMesh sb;
        sb.eftId = bvRenderer->addEffect("Tutorial04.fx");
        //sb.eftId = bvRenderer->addEffect("SimpleShader.fx");
        sb.techName = "Render";

        //bvRenderer->setShaderVariable(sb.eftId, g_pWorldVariable, "World");
        // Obtain the variables
        ID3D10Effect* eft = bvRenderer->GetEffectById(sb.eftId);
        g_pWorldVariable = eft->GetVariableByName( "World" )->AsMatrix();
        g_pViewVariable = eft->GetVariableByName( "View" )->AsMatrix();
        g_pProjectionVariable = eft->GetVariableByName( "Projection" )->AsMatrix();

        D3D10_PASS_DESC PassDesc;
        bvRenderer->GetTechniquePassByIndexDesc(&PassDesc, sb.eftId, sb.techName, 0);

        FormatDesc fd[2] = 
        {
            {0, TYPE_VERTEX, FORMAT_FLOAT, 3},
            {0, TYPE_COLOR, FORMAT_FLOAT, 4},
        };
        sb.vfId = bvRenderer->addVertexFormat(fd, 2, &PassDesc);
        bvRenderer->setVertexFormat(sb.vfId);
        SimpleVertex vertices[] =
        {
            { D3DXVECTOR3( -1.0f, 1.0f, -1.0f ), D3DXVECTOR4( 0.0f, 0.0f, 1.0f, 1.0f ) },
            { D3DXVECTOR3( 1.0f, 1.0f, -1.0f ), D3DXVECTOR4( 0.0f, 1.0f, 0.0f, 1.0f ) },
            { D3DXVECTOR3( 1.0f, 1.0f, 1.0f ), D3DXVECTOR4( 0.0f, 1.0f, 1.0f, 1.0f ) },
            { D3DXVECTOR3( -1.0f, 1.0f, 1.0f ), D3DXVECTOR4( 1.0f, 0.0f, 0.0f, 1.0f ) },
            { D3DXVECTOR3( -1.0f, -1.0f, -1.0f ), D3DXVECTOR4( 1.0f, 0.0f, 1.0f, 1.0f ) },
            { D3DXVECTOR3( 1.0f, -1.0f, -1.0f ), D3DXVECTOR4( 1.0f, 1.0f, 0.0f, 1.0f ) },
            { D3DXVECTOR3( 1.0f, -1.0f, 1.0f ), D3DXVECTOR4( 1.0f, 1.0f, 1.0f, 1.0f ) },
            { D3DXVECTOR3( -1.0f, -1.0f, 1.0f ), D3DXVECTOR4( 0.0f, 0.0f, 0.0f, 1.0f ) },
        };
        sb.vbId = bvRenderer->addVertexBuffer(vertices, sizeof(vertices));
        bvRenderer->setVertexBuffer(0, sb.vfId, sb.vbId, 0);

        // Create index buffer
        DWORD indices[] =
        {
            3,1,0,
            2,1,3,

            0,5,4,
            1,5,0,

            3,4,7,
            0,4,3,

            1,6,5,
            2,6,1,

            2,7,6,
            3,7,2,

            6,4,5,
            7,4,6,
        };

        uint nIndices = sizeof(indices)/sizeof(DWORD);
        sb.ibId = bvRenderer->addIndexBuffer(indices, nIndices, sizeof(DWORD), DEFAULT);
        bvRenderer->setIndexBuffer(sb.ibId);

        SubMesh sb2(sb);
        bvRenderer->addSubMesh(sb);
        bvRenderer->addSubMesh(sb2);

        // Initialize the world matrix
        D3DXMatrixIdentity( &g_World );
        D3DXMatrixIdentity( &g_World2 );

        // Initialize the view matrix
        D3DXVECTOR3 Eye( 0.0f, 1.0f, -7.0f );
        D3DXVECTOR3 At( 0.0f, 1.0f, 0.0f );
        D3DXVECTOR3 Up( 0.0f, 1.0f, 0.0f );
        D3DXMatrixLookAtLH( &g_View, &Eye, &At, &Up );

        RECT rc;
        GetClientRect( pimpl->d_window, &rc );
        UINT width = rc.right - rc.left;
        UINT height = rc.bottom - rc.top;

        // Initialize the projection matrix
        D3DXMatrixPerspectiveFovLH( &g_Projection, ( float )D3DX_PI * 0.5f, width / ( FLOAT )height, 0.1f, 100.0f );


        return hr;
    }

    void drawPerFrame()
    {
        updateMatrix();

        g_pWorldVariable->SetMatrix( ( float* )&g_World );
        g_pViewVariable->SetMatrix( ( float* )&g_View );
        g_pProjectionVariable->SetMatrix( ( float* )&g_Projection );

        bvRenderer->drawSubMesh(0, PRIM_TRIANGLES, 36, 0, 8, 0);

        //
        // Update variables for the second cube
        //
        g_pWorldVariable->SetMatrix( ( float* )&g_World2 );
        //g_pViewVariable->SetMatrix( ( float* )&g_View );
        //g_pProjectionVariable->SetMatrix( ( float* )&g_Projection );

        bvRenderer->drawSubMesh(1, PRIM_TRIANGLES, 36, 0, 8, 0);
    }

    void updateMatrix()
    {
        // Update our time
        static float t = 0.0f;
        int g_driverType = 0;
        if( g_driverType == D3D10_DRIVER_TYPE_REFERENCE )
        {
            t += ( float )D3DX_PI * 0.0125f;
        }
        else
        {
            static DWORD dwTimeStart = 0;
            DWORD dwTimeCur = GetTickCount();
            if( dwTimeStart == 0 )
                dwTimeStart = dwTimeCur;
            t = ( dwTimeCur - dwTimeStart ) / 1000.0f;
        }

        //
        // Animate the cube
        //
        D3DXMatrixRotationY( &g_World, t );

        // 2nd Cube:  Rotate around origin
        D3DXMATRIX mTranslate;
        D3DXMATRIX mOrbit;
        D3DXMATRIX mSpin;
        D3DXMATRIX mScale;
        D3DXMatrixRotationZ( &mSpin, -t );
        D3DXMatrixRotationY( &mOrbit, -t * 2.0f );
        D3DXMatrixTranslation( &mTranslate, -4.0f, 0.0f, 0.0f );
        D3DXMatrixScaling( &mScale, 0.3f, 0.3f, 0.3f );

        D3DXMatrixMultiply( &g_World2, &mScale, &mSpin );
        D3DXMatrixMultiply( &g_World2, &g_World2, &mTranslate );
        D3DXMatrixMultiply( &g_World2, &g_World2, &mOrbit );

    }
};

#endif //SIMPLEAPP3_H_